

#include "mainwindow.hpp"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QTimer>
#include <QBoxLayout>
#include <QTextStream>
#include <QFileDialog>
#include <QFileInfo>
#include <QDockWidget>
#include <QListWidget>
#include <QListWidgetItem>
#include <QTextBrowser>
#include <QPluginLoader>
#include <QApplication>
#include <QSettings>
#include <QVariantMap>

#include <functional>

#include <QtConcurrent/QtConcurrentRun>
#include <QFuture>
#include <QFutureWatcher>

#include <qlogger.hpp>
#include "interfaces.hpp"

#include "dsp_test.hpp"
#include "qfftwindow.hpp"
#include "modhertzelwindow.hpp"
#include "plot_panel.hpp"
#include <genpanel.hpp>
#include "testdatadialog.hpp"
#include "transformwindow.hpp"
#include "dataobject/dataobject.hpp"
#include "utils.hpp"

#include <qwt_plot_marker.h>
#include <qwt_symbol.h>

#include <boost/range.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/range/algorithm/sort.hpp>
namespace rng = boost::range;

namespace
{
QLogger * l = QLoggerEngine::getLogger("Core");
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ctrateToolBars();
    m_tabs = new QTabWidget(this);

    QVBoxLayout * layout = new QVBoxLayout();

    layout->addWidget(m_tabs);
    ui->centralWidget->setLayout(layout);

    m_taskList = new QListWidget();
    addDock(QString(tr("Открытые файлы")), m_taskList);

    m_fft_wnd = new QFFTWindow();
    addDock(tr("Окно преобразования"), m_fft_wnd);
    connect(m_fft_wnd, SIGNAL(fft_window(int,int)), this, SLOT(recountFFT(int,int)) );

    m_Hertzel_wnd = new QModHertzelWindow();
    addDock(tr("Параметры Герцеля"), m_Hertzel_wnd);
    //connect(m_fft_wnd, SIGNAL(fft_window(int,int)), this, SLOT(recountFFT(int,int)) );
    connect(m_Hertzel_wnd, SIGNAL(recalcHertzel()), this, SLOT(count_mod_gertzel()) );

    connect(m_taskList, SIGNAL(currentRowChanged(int)), this, SLOT(setCurrent(int)) );
    connect(m_tabs,     SIGNAL(currentChanged(int)), this, SLOT(setCurrent(int)) );

    //FIXME :  stil not realized
//    m_genPanel = new TGenPanel();
//    addDock(tr("Генераторы"), m_genPanel);

    m_transform_wnd = new TransformWindow();
    addDock(tr("Функции"), m_transform_wnd);
    connect(m_transform_wnd, SIGNAL(zoneChanged(double,double)), this, SLOT(onZoneChanged(double,double)) );

    m_transform_pulse_wnd = new TransformWindow();
    addDock(tr("Поиск начала"), m_transform_pulse_wnd);
    m_transform_pulse_wnd->setSettingsGroup("transform_pulse_window");


    m_logBrowser = new QTextBrowser();
    addDock(tr("Log messages"), m_logBrowser, Qt::BottomDockWidgetArea);

    QLoggerObjectAppender * objAppender = new QLoggerObjectAppender(127, "%d - <%l> - {%c} - %m");
    l->addAppender(objAppender);
    connect(objAppender, SIGNAL(logStr(QString)), this, SLOT(addLogMessage(QString)) );

    loadPlugins();

    this->loadWndState();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::ctrateToolBars()
{
    m_mainToolBar = new QToolBar(this);
    m_mainToolBar->setObjectName("main_toolbar");

    QIcon icon;
    m_openWaveAct = new QAction(tr("Открыть"),this);
    icon.addPixmap(QPixmap(tr(":/image/add.png")), QIcon::Normal, QIcon::Off);
    m_openWaveAct->setIcon(icon);
    connect(m_openWaveAct, SIGNAL(triggered()), this, SLOT(openWave()));

    m_addTestDataAct = new QAction(tr("TstDat"), this);
    connect(m_addTestDataAct, SIGNAL(triggered()), this, SLOT(loadTestData()) );
    icon.addPixmap(QPixmap(tr(":/image/chart_curve_add.png")), QIcon::Normal, QIcon::Off);
    m_addTestDataAct->setIcon(icon);

    m_startTransformAct = new QAction(tr("Преобразовать"),this);
    m_startTransformAct->setShortcut(QKeySequence("Ctrl+T"));
    m_startTransformAct->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_startTransformAct, SIGNAL(triggered()), this, SLOT(startTransform()) );
    icon.addPixmap(QPixmap(tr("://image/funct.png")), QIcon::Normal, QIcon::Off);
    m_startTransformAct->setIcon(icon);

    m_setZeroLenghtAct = new QAction(tr("Set Zero Len"), this);
    m_setZeroLenghtAct->setShortcut(QKeySequence("Ctrl+L"));
    m_setZeroLenghtAct->setShortcutContext(Qt::ApplicationShortcut);
    connect(m_setZeroLenghtAct, &QAction::triggered, [this](bool){base_time = last_calc_base_time;logInfo(l)
                                                                  << "Set base time to " << base_time;});
    this->addAction(m_setZeroLenghtAct);

    m_mainToolBar->addAction(m_openWaveAct);
    m_mainToolBar->addAction(m_addTestDataAct);
    m_mainToolBar->addAction(m_startTransformAct);

    addToolBar(Qt::TopToolBarArea, m_mainToolBar);
}

void MainWindow::addDock(QString title, QWidget *w, Qt::DockWidgetArea area)
{
    QDockWidget * dock = new QDockWidget(title, this);
    dock->setObjectName(title.replace(QString(" "),QString("_"),Qt::CaseInsensitive));
    dock->setWidget(w);
    this->addDockWidget(area, dock);
}

void MainWindow::openWave()
{
    //TODO: реализовать функцию.
    QStringList filters;
    QStringList formatKeys = formatPlugins_.keys();
    QStringList fk = saveLoadObjectPlugins_.keys();
    std::for_each(formatKeys.begin(),formatKeys.end(), [&filters,this](const QString & k){filters += formatPlugins_[k]->fileFilter();});
    std::for_each(fk.begin(),fk.end(),
                  [&filters,this](const QString & k){filters += saveLoadObjectPlugins_[k]->fileFilter();});

    QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Открыть файл..."), last_opened_dir_/*, filters.join(";;")*/);
    if(fileNames.size())
        {
            QFileInfo fi(fileNames.at(0));
            last_opened_dir_ = fi.absoluteDir().absolutePath();
            for(const auto& fileName : fileNames)
                {
                    QFileInfo fi(fileName);
                    auto key = std::find_if(formatKeys.begin(),formatKeys.end(), [&](const QString & k)
                                            {return formatPlugins_[k]->formats().contains(fi.suffix());} );
                    if(key != formatKeys.end())
                        {
                            if(formatPlugins_[(*key)]->read(fileName))
                                {
                                    NamedData * d = new NamedData;
                                    d->name = fi.baseName();
                                    d->sampleRate = formatPlugins_[(*key)]->sampleRate();
                                    d->data = formatPlugins_[(*key)]->getData().toStdVector();
                                    addPanel(d);
                                    formatPlugins_[(*key)]->flush();
                                }
                        }

                    auto key_o = rng::find_if(fk,[&fi,this](const QString & k)
                    {return saveLoadObjectPlugins_[k]->formats().contains(fi.suffix());});
                    if(key_o != fk.end())
                        {
                            QScopedPointer<DataObject> data_obj(
                                                                static_cast<DataObject*>(saveLoadObjectPlugins_[(*key_o)]->
                                                                loadObjectFromFile(fileName)));
                            if(data_obj->dataL()->data.size())
                                {
                                    NamedData * d = new NamedData;
                                    (*d) = (*data_obj->dataL());
                                    d->name = fi.baseName() + "_L";
                                    d->pantry["temperature"] = data_obj->temperature();

                                    addPanel(d);
                                }
                            if(data_obj->dataR()->data.size())
                                {
                                    NamedData * d = new NamedData;
                                    (*d) = (*data_obj->dataR());
                                    d->name = fi.baseName() + "_R";
                                    d->pantry["temperature"] = data_obj->temperature();

                                    addPanel(d);
                                }
                        }
                }
        }
}

void MainWindow::recountFFT(int pos, int width)
{
    if(m_dataList.size() == 0)
        return;

    TPlot * dft_plot = 0;
    TPlotPanel * panel = qobject_cast<TPlotPanel *>(m_tabs->currentWidget());

    if(panel)
        dft_plot = panel->plot(QString("Spectr"));
    else
        return;
    if(dft_plot == 0)
        return;



    QVector<QPointF> series;
    std::vector<std::complex<double> > file_data;
    series.resize(width);
    file_data.resize(width);

    qDebug()<<"FFT, pos:"<<pos<<" width:"<<width;

    if( (m_dataList[m_tabs->currentIndex()]->data.size()) > static_cast<uint>((pos+width)))
        {
            for(int i = 0; i < width; ++i)
                file_data[i] = m_dataList[m_tabs->currentIndex()]->data[i+pos];
        }
    else
        {
            qDebug()<<"uuuuuu--pssssss"<<"data size = "<<m_dataList[m_tabs->currentIndex()]->data.size();
        }


    fft_base(file_data);
    for(int i = 0; i<series.size(); ++i)
        {
            series[i] = (QPointF( (double)i*m_dataList[m_tabs->currentIndex()]->sampleRate/file_data.size()
                                          , std::abs(file_data[i]) ));
        }

    QwtPlotCurve * curve = dft_plot->curve(0);
    if(curve)
        {
            curve->setSamples(series);
        }
    else
        {
            dft_plot->addCurve(m_dataList[m_tabs->currentIndex()]->name, series);
        }
    dft_plot->replot();
}

void MainWindow::setCurrent(int pos)
{
    if(m_tabs->currentIndex() != pos)
        m_tabs->setCurrentIndex(pos);
    if(m_taskList->currentRow() != pos)
        m_taskList->setCurrentRow(pos);

    if(m_dataList.size() > pos)
        {
            m_Hertzel_wnd->setSampleRate(m_dataList[m_tabs->currentIndex()]->sampleRate);
        }

}

void MainWindow::count_mod_gertzel()
{
    if(m_dataList.size() == 0)
        return;

    TPlot * mg_plot = 0;
    TPlotPanel * panel = qobject_cast<TPlotPanel *>(m_tabs->currentWidget());

    if(panel)
        mg_plot = panel->plot(QString("Hertzel"));
    else
        {
            logError(l,tr("не обнаружена панель Герцеля") );
            return;
        }

    if(mg_plot == 0)
        {
            logError(l,tr("Нет графика"));
            return;
        }



    QVector<QPointF> series;
    std::vector<std::complex<double> > file_data;
    std::vector<std::complex<double> > mg_data;
    //series.resize(width);
    //file_data.resize(width);
    int N, k;

    N = m_Hertzel_wnd->bufSize()/*177*/;
    k = m_Hertzel_wnd->harmonikNum()/*100*/;

    boost::circular_buffer<std::complex<double> > buf(N,std::complex<double>(0,0));

    file_data.resize(m_dataList[m_tabs->currentIndex()]->data.size());
    for(uint i = 0; i <  file_data.size(); ++i)
        {
            file_data[i] = m_dataList[m_tabs->currentIndex()]->data[i];
        }

    mod_gertzel(buf, std::complex<double>(0,0), N, k);
    mg_data.resize(file_data.size());
    for(size_t i = 0; i< file_data.size(); ++i)
        {
            mg_data[i] = mod_gertzel(buf, file_data[i], N, k);
        }

    series.resize(file_data.size());
    for(size_t i = 0; i<file_data.size(); ++i)
        {
            series[i] =  QPointF(i/m_dataList[m_tabs->currentIndex()]->sampleRate, std::abs(mg_data[i]) ) ;
        }

    QwtPlotCurve * curve = mg_plot->curve(0);
    if(curve)
        {
            curve->setSamples(series);
        }
    mg_plot->replot();

    logInfo(l, QString("%1 end work").arg(__FUNCTION__));
}

void MainWindow::loadTestData()
{
    TestDataDialog dlg;
    dlg.setList(dataPlugins_.keys());
    if(dlg.exec())
        {
            QString data_key = dlg.getSelected();
            if(dataPlugins_.keys().contains(data_key))
                {
                    NamedData * d = new NamedData;
                    d->name = dataPlugins_[data_key]->name();
                    d->sampleRate = dataPlugins_[data_key]->sampleRate();
                    d->data = dataPlugins_[data_key]->getData().toStdVector();
                    addPanel(d);
                }
        }
}

void MainWindow::addLogMessage(QString txt)
{
    m_logBrowser->append(txt);
}

void MainWindow::startTransform()
{

    if(transformPlugins_.keys().contains(m_transform_wnd->params()["transformation"].toString()) &&
       transformPlugins_.keys().contains(m_transform_pulse_wnd->params()["transformation"].toString()))
        {
            startDoubleCalculation();
            return;
        }

    if(transformIntPlugins_.keys().contains(m_transform_wnd->params()["transformation"].toString()) &&
       transformIntPlugins_.keys().contains(m_transform_pulse_wnd->params()["transformation"].toString()))
        {
            startIntCalculation();
            return;
        }

    logError(l) << QString(tr("Несовместимые плагины преобразований"));

}

void MainWindow::startDoubleCalculation()
{
    delta_t_pulse_  = -1.;
    delta_t_signal_ = -1.;

    if(m_dataList.size() == 0)
        {
            logError(l) << tr("Нет данных !");
            return;
        }

    if(transformPlugins_.keys().contains(m_transform_wnd->params()["transformation"].toString()))
        {
            TransformNamedData* plugin = transformPlugins_[m_transform_wnd->params()["transformation"].toString()];
            NamedData* data = m_dataList[m_tabs->currentIndex()].data();
            QVariantMap par = m_transform_wnd->params();
            par["id"] = "signal";
            if(data->name[data->name.size() - 1] == 'L')
                par["pattern_file"] = par["pattern_left_file"];
            else
                par["pattern_file"] = par["pattern_right_file"];
            par["prev_time"] = last_calc_time_;
            QFutureWatcher<NamedData*> * watcher = new QFutureWatcher<NamedData*>() ;
            connect(watcher, SIGNAL(finished()), this, SLOT(computationFinished()), Qt::QueuedConnection );
            watcher->setFuture( QtConcurrent::run( std::bind(&TransformNamedData::transform,plugin,std::placeholders::_1
                                                             ,std::placeholders::_2),data,par ) );
        }
    if(transformPlugins_.keys().contains(m_transform_pulse_wnd->params()["transformation"].toString()))
        {
            TransformNamedData* plugin = transformPlugins_[m_transform_pulse_wnd->params()["transformation"].toString()];
            NamedData* data = m_dataList[m_tabs->currentIndex()].data();
            QVariantMap par = m_transform_pulse_wnd->params();
            par["id"] = "pulse";
            par["pattern_file"] = par["pattern_left_file"];
            par["prev_time"] = last_calc_pulse_time_;
            QFutureWatcher<NamedData*> * watcher = new QFutureWatcher<NamedData*>() ;
            connect(watcher, SIGNAL(finished()), this, SLOT(computationFinished()), Qt::QueuedConnection );
            watcher->setFuture( QtConcurrent::run( std::bind(&TransformNamedData::transform,plugin,std::placeholders::_1
                                                             ,std::placeholders::_2),data,par ) );
        }
}

void MainWindow::startIntCalculation()
{
    delta_t_pulse_  = -1.;
    delta_t_signal_ = -1.;

    if(m_dataList.size() == 0)
        {
            logError(l) << tr("Нет данных !");
            return;
        }

    if(transformIntPlugins_.keys().contains(m_transform_wnd->params()["transformation"].toString()))
        {
            TransformNamedIntData* plugin = transformIntPlugins_[m_transform_wnd->params()["transformation"].toString()];
            NamedIntData* data = new NamedIntData(m_dataList[m_tabs->currentIndex()].data());
            QVariantMap par = m_transform_wnd->params();
            par["id"] = "signal";
            if(data->name[data->name.size() - 1] == 'L')
                par["pattern_file"] = par["pattern_left_file"];
            else
                par["pattern_file"] = par["pattern_right_file"];
            par["prev_time"] = last_calc_time_;
            QFutureWatcher<NamedIntData*> * watcher = new QFutureWatcher<NamedIntData*>() ;
            connect(watcher, SIGNAL(finished()), this, SLOT(computationFinished()), Qt::QueuedConnection );
            watcher->setFuture( QtConcurrent::run( std::bind(&TransformNamedIntData::transform,plugin,std::placeholders::_1
                                                             ,std::placeholders::_2),data,par ) );
        }
    if(transformIntPlugins_.keys().contains(m_transform_pulse_wnd->params()["transformation"].toString()))
        {
            TransformNamedIntData* plugin = transformIntPlugins_[m_transform_pulse_wnd->params()["transformation"].toString()];
            NamedIntData* data = new NamedIntData(m_dataList[m_tabs->currentIndex()].data());
            QVariantMap par = m_transform_pulse_wnd->params();
            par["id"] = "pulse";
            par["pattern_file"] = par["pattern_left_file"];
            par["prev_time"   ] = last_calc_pulse_time_;
            QFutureWatcher<NamedIntData*> * watcher = new QFutureWatcher<NamedIntData*>() ;
            connect(watcher, SIGNAL(finished()), this, SLOT(computationFinished()), Qt::QueuedConnection );
            watcher->setFuture( QtConcurrent::run( std::bind(&TransformNamedIntData::transform,plugin,std::placeholders::_1
                                                             ,std::placeholders::_2),data,par ) );
        }
}

void MainWindow::computationFinished()
{
    QFutureWatcher<NamedData*> *    watcher     = dynamic_cast<QFutureWatcher<NamedData*> *>   (this->sender());
    QFutureWatcher<NamedIntData*> * watcher_int = dynamic_cast<QFutureWatcher<NamedIntData*> *>(this->sender());

    if(watcher)
        {
            processTransformResult(QSharedPointer<NamedData>(watcher->result()));
            watcher->deleteLater();
        }
    else if(watcher_int)
        {
            processTransformResult(QSharedPointer<NamedIntData>(watcher_int->result()));
            watcher_int->deleteLater();
        }
    else
        {
            logError(l) << "ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR";
        }
}

void MainWindow::processTransformResult(QSharedPointer<NamedData> result)
{
    QSharedPointer<NamedData> transf_data = QSharedPointer<NamedData>(result);
    TPlotPanel* panel = qobject_cast<TPlotPanel*>(m_tabs->currentWidget());
    NamedData*  data  = m_dataList[m_tabs->currentIndex()].data();
    TPlot*      plot  = panel->plot(data->name);
    if(transf_data->pantry["id"].toString() ==  "signal")
        {
            m_transformDataList.append(transf_data);

            QVector<QPointF> series;
            series.resize(transf_data->data.size());
            for(size_t i = 0; i < transf_data->data.size(); ++i)
                series[i] = QPointF(i/transf_data->sampleRate,transf_data->data[i].real());

            if(transf_data->pantry["ansver_idx"].toInt() >= series.size())
                transf_data->pantry["ansver_idx"] = 0;

            if(transf_data->pantry["ansver_idx"].toInt() < series.size())
                delta_t_signal_ = series[transf_data->pantry["ansver_idx"].toInt()].rx() ;

            logInfo(l) << "Delta signal = " << delta_t_signal_
                       << " Iter count = " << transf_data->pantry["iter_count"].toInt();;

            QwtPlotMarker* marker = new QwtPlotMarker();
            marker->setValue( series[transf_data->pantry["ansver_idx"].toInt()].rx(),
                    series[transf_data->pantry["ansver_idx"].toInt()].ry() );
            marker->setLineStyle     ( QwtPlotMarker::VLine );
            marker->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
            marker->setLinePen       ( Qt::green, 0, Qt::DashDotLine );

            marker->setSymbol( new QwtSymbol( QwtSymbol::Diamond,
                                              QColor( Qt::blue ),
                                              QColor( Qt::green ),
                                              QSize( 4, 4 ) ) );

            marker->attach( plot->plot() );
            plot->addCurve(transf_data->name, series);
        }
    if(transf_data->pantry["id"].toString() ==  "pulse")
        {
            delta_t_pulse_ = transf_data->pantry["ansver_idx"].toInt() /  (double)transf_data->sampleRate;
            logInfo(l) << "Delta pulse = " << delta_t_pulse_
                       << " Iter count = " << transf_data->pantry["iter_count"].toInt();

            QwtPlotMarker* marker = new QwtPlotMarker();
            marker->setValue         ( delta_t_pulse_,2045.0 );
            marker->setLineStyle     ( QwtPlotMarker::VLine );
            marker->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
            marker->setLinePen       ( Qt::red, 0, Qt::DashDotLine );

            marker->setSymbol( new QwtSymbol( QwtSymbol::Diamond,
                                              QColor( Qt::yellow ),
                                              QColor( Qt::red ),
                                              QSize( 4, 4 ) ) );

            marker->attach( plot->plot() );
        }

    if(delta_t_signal_ > 0. && delta_t_pulse_ > 0.)
        {
            //double delta_V = ( L / ( base_time + (delta_t_signal - delta_t_pulse - base_time) ) ) - V ;
            double L = plugin_utils::sound_speed(273.15 + base_temp_) * base_time;
            last_calc_time_ = delta_t_signal_;
            last_calc_pulse_time_ = delta_t_pulse_;
            last_calc_base_time = ( delta_t_signal_ - delta_t_pulse_);
            double delta_V = ( L / last_calc_base_time ) - plugin_utils::sound_speed(273.15 + base_temp_) ;

            logInfo(l) << QString("Решение для %1 \t= %2,\tV = %3\tL=%4 \tdV = %5")
                          .arg(transf_data->name)
                          .arg(last_calc_base_time,0,'f',20)
                          .arg(plugin_utils::sound_speed(273.15 + base_temp_))
                          .arg(plugin_utils::sound_speed(273.15 + base_temp_) * last_calc_base_time,0,'f',20)
                          .arg(delta_V) ;
        }

    plot->replot();
}

void MainWindow::processTransformResult(QSharedPointer<NamedIntData> result)
{
    QSharedPointer<NamedIntData> transf_data = QSharedPointer<NamedIntData>(result);
    TPlotPanel* panel = qobject_cast<TPlotPanel*>(m_tabs->currentWidget());
    NamedData*  data  = m_dataList[m_tabs->currentIndex()].data();
    TPlot*      plot  = panel->plot(data->name);

    if(transf_data->pantry["id"].toString() ==  "signal")
        {
            QSharedPointer<NamedData> dat = QSharedPointer<NamedData>(new NamedData);
            (*dat) = (*transf_data);
            m_transformDataList.append(dat);

            QVector<QPointF> series;
            series.resize(transf_data->data.size());
            for(size_t i = 0; i < transf_data->data.size(); ++i)
                series[i] = QPointF(static_cast<double>(i)/transf_data->sampleRate,transf_data->data[i]);

            if(transf_data->pantry["ansver_idx"].toInt() >= series.size())
                transf_data->pantry["ansver_idx"] = 0;

            if(transf_data->pantry["ansver_idx"].toInt() < series.size())
                delta_t_signal_ = series[transf_data->pantry["ansver_idx"].toInt()].rx() ;

            logInfo(l) << "Delta signal = " << delta_t_signal_
                       << " Iter count = " << transf_data->pantry["iter_count"].toInt();;

            QwtPlotMarker* marker = new QwtPlotMarker();
            marker->setValue( series[transf_data->pantry["ansver_idx"].toInt()].rx(),
                    series[transf_data->pantry["ansver_idx"].toInt()].ry() );
            marker->setLineStyle     ( QwtPlotMarker::VLine );
            marker->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
            marker->setLinePen       ( Qt::green, 0, Qt::DashDotLine );

            marker->setSymbol( new QwtSymbol( QwtSymbol::Diamond,
                                              QColor( Qt::blue ),
                                              QColor( Qt::green ),
                                              QSize( 4, 4 ) ) );

            marker->attach( plot->plot() );
            plot->addCurve(transf_data->name, series);
        }
    if(transf_data->pantry["id"].toString() ==  "pulse")
        {
            delta_t_pulse_ = transf_data->pantry["ansver_idx"].toInt() /  (double)transf_data->sampleRate;
            logInfo(l) << "Delta pulse = " << delta_t_pulse_
                       << " Iter count = " << transf_data->pantry["iter_count"].toInt();

            QwtPlotMarker* marker = new QwtPlotMarker();
            marker->setValue         ( delta_t_pulse_,2045.0 );
            marker->setLineStyle     ( QwtPlotMarker::VLine );
            marker->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
            marker->setLinePen       ( Qt::red, 0, Qt::DashDotLine );

            marker->setSymbol( new QwtSymbol( QwtSymbol::Diamond,
                                              QColor( Qt::yellow ),
                                              QColor( Qt::red ),
                                              QSize( 4, 4 ) ) );

            marker->attach( plot->plot() );
        }

    if(delta_t_signal_ > 0. && delta_t_pulse_ > 0.)
        {
            //double delta_V = ( L / ( base_time + (delta_t_signal - delta_t_pulse - base_time) ) ) - V ;
            double L = plugin_utils::sound_speed(273.15 + base_temp_) * base_time;
            last_calc_time_ = delta_t_signal_;
            last_calc_pulse_time_ = delta_t_pulse_;
            last_calc_base_time = ( delta_t_signal_ - delta_t_pulse_);
            double delta_V = ( L / last_calc_base_time ) - plugin_utils::sound_speed(273.15 + base_temp_) ;

            logInfo(l) << QString("Решение для %1 \t= %2,\tV = %3\tL=%4 \tdV = %5")
                          .arg(transf_data->name)
                          .arg(last_calc_base_time,0,'f',20)
                          .arg(plugin_utils::sound_speed(273.15 + base_temp_))
                          .arg(plugin_utils::sound_speed(273.15 + base_temp_) * last_calc_base_time,0,'f',20)
                          .arg(delta_V) ;
        }

    plot->replot();
}

void MainWindow::onZoneChanged(double s, double e)
{
    if(m_dataList.size() == 0)
        return;
    TPlotPanel* panel = qobject_cast<TPlotPanel*>(m_tabs->currentWidget());
    TPlot* plot = panel->plot(m_dataList[m_tabs->currentIndex()].data()->name);
    if(plot)
        plot->setZone(s,e);
}

void MainWindow::loadPlugins()
{
    QDir pluginsDir = QDir(qApp->applicationDirPath());
    pluginsDir.cd("plugins");
    foreach (QString fileName, pluginsDir.entryList(QDir::Files))
        {
            QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
            QObject *plugin = loader.instance();
            if (plugin)
                {
                    pluginFileNames_ += fileName;
                    logInfo(l,QString(tr("Загружен плагин %1")).arg(fileName));
                    populatePlugins(plugin);
                }
        }

    auto keys = transformPlugins_.keys();
    keys += transformIntPlugins_.keys();
    std::sort(keys.begin(),keys.end(),std::less<QString>());
    std::for_each(keys.cbegin(),keys.cend(),[=](const QString& s){m_transform_wnd->addTransformation(s);});
    m_transform_wnd->loadConfig();
    std::for_each(keys.cbegin(),keys.cend(),[=](const QString& s){m_transform_pulse_wnd->addTransformation(s);});
    m_transform_pulse_wnd->loadConfig();
}

void MainWindow::populatePlugins(QObject * plugin)
{
    if(plugin)
        {
            DataInterface * iData = qobject_cast<DataInterface *>(plugin);
            if(iData)
                dataPlugins_[iData->name()] = iData;

            ReadFileFormatInterface * iFormat = qobject_cast<ReadFileFormatInterface *>(plugin);
            if(iFormat)
                formatPlugins_[iFormat->name()] = iFormat;

            SaveFileFormatInterface* iSaveFormat = qobject_cast<SaveFileFormatInterface *>(plugin);
            if(iSaveFormat)
                saveFormatPlugins_[iSaveFormat->name()] = iSaveFormat;

            TransformNamedData* iTransform = qobject_cast<TransformNamedData*>(plugin);
            if(iTransform)
                {
                    transformPlugins_[iTransform->name()] = iTransform;
                    m_transform_wnd->updatePatternList(iTransform->patternList());
                    m_transform_pulse_wnd->updatePatternList(iTransform->patternList());
                }

            TransformNamedIntData* iTransformInt = qobject_cast<TransformNamedIntData*>(plugin);
            if(iTransformInt)
                {
                    transformIntPlugins_[iTransformInt->name()] = iTransformInt;
                    m_transform_wnd->updatePatternList(iTransformInt->patternList());
                    m_transform_pulse_wnd->updatePatternList(iTransformInt->patternList());
                }

            SaveLoadObjectInterface* iSaveLoadObject = qobject_cast<SaveLoadObjectInterface*>(plugin);
            if(iSaveLoadObject)
                saveLoadObjectPlugins_[iSaveLoadObject->name()] = iSaveLoadObject;
        }
}

void MainWindow::addPanel(NamedData *dat)
{
    m_dataList.append(QSharedPointer<NamedData>(dat));

    TPlot * plot       = nullptr;
    TPlot * dft_plot   = nullptr;
    TPlot * hertz_plot = nullptr;

    TPlotPanel* panel = new TPlotPanel();
    m_tabs->addTab(panel, dat->name);
    plot       = panel->addPlot(QString("%1").arg(dat->name),0,0,1,2);
    dft_plot   = panel->addPlot(QString("%1 - Spectr").arg(dat->name),1,0);
    hertz_plot = panel->addPlot(QString("%1 - Hertzel").arg(dat->name),1,1);
    panel->grid()->setRowStretch(0,3);
    panel->grid()->setRowStretch(1,1);

    QListWidgetItem * item;
    item = new QListWidgetItem();
    m_taskList->addItem(item);
    item->setText(dat->name);

    QVector<QPointF> series;
    series.resize(dat->data.size());
    for(size_t i = 0; i < dat->data.size(); ++i)
        series[i] = QPointF(i/dat->sampleRate,dat->data[i].real());

    plot->addCurve(dat->name, series);
    plot->replot();

    dft_plot->addCurve(dat->name, series);
    dft_plot->replot();

    hertz_plot->addCurve(dat->name, series);
    hertz_plot->replot();

}

void MainWindow::closeEvent(QCloseEvent *event)
{
    saveWndState();
    QMainWindow::closeEvent(event);
}

void MainWindow::saveWndState()
{
    QSettings settings;
    settings.beginGroup("main_window");
    settings.setValue("geometry", saveGeometry());
    settings.setValue("windowState", saveState());
    settings.setValue("last_opened_dir",last_opened_dir_);
    settings.endGroup();

    settings.beginGroup("wind_calculus");
    settings.setValue("base_time",base_time);
    settings.endGroup();


    m_transform_wnd->saveConfig(&settings);
    m_transform_pulse_wnd->saveConfig(&settings);
}

void MainWindow::loadWndState()
{
    QSettings settings;
    settings.beginGroup("main_window");
    restoreGeometry(settings.value("geometry").toByteArray());
    restoreState   (settings.value("windowState").toByteArray());
    last_opened_dir_ = settings.value("last_opened_dir").toString();
    settings.endGroup();

    settings.beginGroup("wind_calculus");
    base_time = settings.value("base_time", 0.0001).toDouble();
    settings.endGroup();
}

